<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>拖动排序</title>
    <style>
        body {
            margin: 0;
            padding: 0;
        }
        .box {
            display: flex;
            font-size: 15px;
        }
        .items {
            margin: 20px 30px;
            position: relative;
            background-color: #f6f9fa;
            overflow: hidden;
            border-radius: 4px;
        }
        .item {
            width: 100px;
            height: 32px;
            line-height: 32px;
            text-align: center;
            transition: background-color .3s, color .3s, box-shadow .5s;
            cursor: pointer;
            user-select: none;
            -moz-user-select: none;
            -ms-user-select: none;
            -webkit-user-select: none;
        }
        .item:hover {
            background-color: #00a1d6;
            color: #fff;
        }
        .select {
            position: absolute;
            background-color: #00a1d6;
            color: #fff;
            box-shadow: 0 4px 4px #ccc;
            z-index: 999;
        }
        .hold {
            cursor: inherit;
            border: 1px dashed #ccc;
            box-sizing: border-box;
            animation: hold-higther 200ms ease-in;
        }
        @keyframes hold-higther {
            0% {
                transform: scale(.4);
            }
            100% {
                transform: scale(1);
            }
        }
    </style>
</head>

<body>
<div class="box"></div>
<script>
    const $ = selectors => document.querySelector(selectors);
    const $$ = selectors => document.querySelectorAll(selectors);
    const navList = ['小强1', '小明2', '小红3', '小绿4', '小白5', '小紫6'];
    const holdItemDom = document.createElement('div');
    holdItemDom.classList.add('item', 'hold');
    const listDom = document.createElement('div');
    listDom.classList.add('items');
    navList.forEach((v, i, arr) => {
        const itemDom = document.createElement('div');
    itemDom.classList.add('item');
    itemDom.dataset.sortindex = i;
    itemDom.textContent = v;
    listDom.appendChild(itemDom);
    });
    $('.box').appendChild(listDom);
    //主要代码
    var dragObj;
    //考虑到item数量会很多，不需要给每个item单独绑定mousedown,mousemove,mouseup事件
    listDom.onmousedown = (event) => {
        let currenIndex, previousIndex;
        const itemDomList = $$('.items .item');
        const listLength = navList.length;
        const startY = event.clientY;
        //找到mousedown的item
        let selectIndex;
        dragObj = event.target;
        Array.from(itemDomList).forEach((v, i) => {
            if (v === event.target) {
            selectIndex = i;
        }
    });
        dragObj.after(holdItemDom);
        dragObj.classList.add('select');
        dragObj.style.top = dragObj.clientHeight * selectIndex + 'px';
        const itemHeight = dragObj.clientHeight;
        let topIndex = selectIndex;
        const startTop = dragObj.style.top;

        previousIndex = Math.ceil((parseInt(startTop) - itemHeight / 2) / itemHeight);
        document.onmousemove = function (event) {
            dragObj.classList.add('select');
            const moveY = event.clientY;
            const presentTop = parseInt(startTop) + (moveY - startY);
            dragObj.style.top = presentTop + 'px';
            currenIndex = Math.ceil((presentTop - itemHeight / 2) / itemHeight);
            if (currenIndex < 0) currenIndex = 0;
            if (currenIndex > listLength - 1) currenIndex = listLength - 1;
            if (previousIndex !== currenIndex) {
                holdItemDom.remove();
                if (previousIndex > currenIndex && currenIndex < topIndex) {
                    dragObj.remove();
                    itemDomList[currenIndex].before(dragObj);
                    dragObj.after(holdItemDom);
                } else {
                    const currentItems = $$('.box .item');
                    currentItems[currenIndex].after(holdItemDom);
                }
                previousIndex = currenIndex;
                if (currenIndex < topIndex) topIndex = currenIndex;
            }
        };
        document.onmouseup = function (event) {
            const currentItems = $$('.box .item');
            if (currenIndex > topIndex) {
                currentItems[currenIndex].after(dragObj);
            }
            holdItemDom.remove();
            dragObj.classList.remove('select');
            dragObj.removeAttribute('style');
            document.onmousemove = null;
            document.onmouseup = null;
        }
    };
</script>
</body>

</html>